package com.dxl.common.utils;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * 日期工具类
 * @author 邓小林
 */
public final class DateUtils {
	public static final String DF_yyyy = "yyyy";
	public static final String DF_yyyyMM = "yyyyMM";
	public static final String DF_yyyyww = "yyyyww";
	public static final String DF_yyyyMMdd = "yyyyMMdd";
	public static final String DF_yyyy_MM_dd = "yyyy-MM-dd";
	public static final String DF_yyyyMMddHH = "yyyyMMddHH";
	public static final String DF_yyyyMMddHHmm = "yyyyMMddHHmm";
	public static final String DF_yyyyMMddHHmmss = "yyyyMMddHHmmss";
	public static final String DF_yyyyMMddHHmmssSSS = "yyyyMMddHHmmssSSS";
	
	/**
	 * 格式化日期
	 * @param date   日期
	 * @param format 格式
	 * @return
	 */
	public static String formatDate(Date date, String format) {
		if (Utils.isNull(date) || Utils.isBlank(format)) {
			return "";
		}
		return new SimpleDateFormat(format).format(date);
	}
	
	/**
	 * 格式化日期
	 * @param milliseconds   毫秒数
	 * @param format 格式
	 * @return
	 */
	public static String formatDate(Long milliseconds, String format) {
		if (Utils.isNull(milliseconds) || Utils.isBlank(format)) {
			return "";
		}
		return new SimpleDateFormat(format).format(new Date(milliseconds));
	}
	
	/**
	 * 解析日期
	 * @param date   日期字符串
	 * @param format 格式
	 * @return
	 */
	public static Date parseDate(String date, String format) {
		if (Utils.isBlank(date) || Utils.isBlank(format)) {
			return null;
		}
		try {
			return new SimpleDateFormat(format).parse(date);
		} catch (Exception e) {
			return null;
		}
	}
	
	/**
	 * 当月的最后一天
	 * @param date   日期
	 * @return
	 */
	public static Date lastDayOfMonth(Date date) {
		try {
			Calendar c = Calendar.getInstance();
			c.setTime(date);
			c.set(Calendar.DAY_OF_MONTH, c.getActualMaximum(Calendar.DAY_OF_MONTH));
			return c.getTime();
		} catch (Exception e) {
			// ignore
		}
		return null;
	}
	
	/**
	 * 计算天数
	 * @param begin 开始日期毫秒数
	 * @param end   结束日期毫秒数
	 * @return
	 */
	public static int calcDays(Long begin, Long end) {
		if (Utils.isNull(begin) || Utils.isNull(end) || begin > end) {
			return 0;
		}
		Date beginDate = new Date(begin), endDate = new Date(end);
		Calendar c = Calendar.getInstance();
		c.setTime(beginDate);
		int i = 0;
		while (c.getTime().equals(endDate) || c.getTime().before(endDate)) {
			++i;
			c.add(Calendar.DAY_OF_MONTH, 1);
		}
		return i;
	}
	
	/**
	 * 判断时间范围是否是天
	 * @param begin   开始日期毫秒数
	 * @param end     结束日期毫秒数
	 * @return
	 */
	public static boolean isDay(Long begin, Long end) {
		if(Utils.isNull(begin) || Utils.isNull(end)) {
			return false;
		}
		String ymd1 = formatDate(new Date(begin), "yyyyMMdd");
		String ymd2 = formatDate(new Date(end), "yyyyMMdd");
		return ymd1.equals(ymd2);
	}
	
	/**
	 * 判断时间范围是否是周
	 * @param begin   开始日期毫秒数
	 * @param end     结束日期毫秒数
	 * @return
	 */
	public static boolean isWeek(Long begin, Long end) {
		if (Utils.isNull(begin) || Utils.isNull(end)) {
			return false;
		}
		Calendar c = Calendar.getInstance();
		c.setTimeInMillis(begin);
		int w1 = c.get(Calendar.WEEK_OF_YEAR);
		int year1 = c.get(Calendar.YEAR);
		int day1 = c.get(Calendar.DAY_OF_WEEK);
		c.setTimeInMillis(end);
		int w2 = c.get(Calendar.WEEK_OF_YEAR);
		int year2 = c.get(Calendar.YEAR);
		int day2 = c.get(Calendar.DAY_OF_WEEK);
		return year1 == year2 
				&& w1 == w2 
				&& day1 == c.getActualMinimum(Calendar.DAY_OF_WEEK) 
				&& day2 == c.getActualMaximum(Calendar.DAY_OF_WEEK);
	}
	
	/**
	 * 判断时间范围是否是月
	 * @param begin   开始日期毫秒数
	 * @param end     结束日期毫秒数
	 * @return
	 */
	public static boolean isMonth(Long begin, Long end) {
		if (Utils.isNull(begin) || Utils.isNull(end)) {
			return false;
		}
		Calendar c = Calendar.getInstance();
		c.setTimeInMillis(begin);
		int day1 = c.get(Calendar.DAY_OF_MONTH);
		int month1 = c.get(Calendar.MONTH);
		int year1 = c.get(Calendar.YEAR);
		c.setTimeInMillis(end);
		int day2 = c.get(Calendar.DAY_OF_MONTH);
		int month2 = c.get(Calendar.MONTH);
		int year2 = c.get(Calendar.YEAR);
		return year1 == year2 
				&& month1 == month2 
				&& day1 == c.getActualMinimum(Calendar.DAY_OF_MONTH) 
				&& day2 == c.getActualMaximum(Calendar.DAY_OF_MONTH);
	}
	
	/**
	 * 时间列表
	 * @param begin 开始时间
	 * @param end   结束时间
	 * @param dateType 日期类型
	 * @param format   格式
	 * @return
	 */
	public static List<String> dateList(Date begin, Date end, DateType dateType, String format) {
		List<String> days = new ArrayList<String>();
		if (Utils.isNull(begin) && Utils.isNull(end)) {
			return days;
		}
		if (Utils.isNull(begin) || Utils.isNull(end)) {
			if (Utils.isNotNull(begin)) {
				days.add(formatDate(begin, format));
			}
			if (Utils.isNotNull(end)) {
				days.add(formatDate(end, format));
			}
			return days;
		}
		return dateList(begin.getTime(), end.getTime(), dateType, format);
	}
	
	/**
	 * 时间列表
	 * @param begin 开始时间
	 * @param end   结束时间
	 * @param dateType 日期类型
	 * @param format   格式
	 * @return
	 */
	public static List<String> dateList(Long begin, Long end, DateType dateType, String format) {
		List<String> days = new ArrayList<String>();
		if (Utils.isNull(begin) && Utils.isNull(end)) {
			return days;
		}
		if (Utils.isNull(begin) || Utils.isNull(end)) {
			if (Utils.isNotNull(begin)) {
				days.add(formatDate(new Date(begin), format));
			}
			if (Utils.isNotNull(end)) {
				days.add(formatDate(new Date(end), format));
			}
			return days;
		}
		Long tmp;
		if (begin > end) {
			tmp = begin;
			begin = end;
			end = tmp;
		}
		if (Utils.isNull(dateType)) {
			dateType = DateType.DAY;
		}
		
		int type = dateType.getType();
		String df = dateType.getFormat();
		Date beginDate = parseDate(formatDate(new Date(begin), df), df), endDate = parseDate(formatDate(new Date(end), df), df);
		Calendar c = Calendar.getInstance();
		c.setTime(beginDate);
		while (c.getTime().before(endDate) || c.getTime().equals(endDate)) {
			days.add(formatDate(c.getTime(), format));
			c.add(type, 1);
		}
		return days;
	}
	
	/**
	 * 日期类型
	 * @author 邓小林
	 */
	public static enum DateType {
		MILLISECOND(Calendar.MILLISECOND, DF_yyyyMMddHHmmssSSS), 
		SECOND(Calendar.SECOND, DF_yyyyMMddHHmmss), 
		MINUTE(Calendar.MINUTE, DF_yyyyMMddHHmm), 
		HOUR(Calendar.HOUR, DF_yyyyMMddHH), 
		DAY(Calendar.DAY_OF_MONTH, DF_yyyyMMdd), 
		WEEK(Calendar.WEEK_OF_MONTH, DF_yyyyww), 
		MONTH(Calendar.MONTH, DF_yyyyMM), 
		YEAR(Calendar.YEAR, DF_yyyy);
		
		DateType(int type, String format) {
			this.type = type;
			this.format = format;
		}
		
		private int type;
		private String format;

		public int getType() {
			return type;
		}

		public String getFormat() {
			return format;
		}
	}
}
